// -----------------------------------------------------------
// Game Framework
// Copyright © 2024-2024 deadcycle. All rights reserved.
// Homepage: https://deadcycle.gitee.io
// Feedback: deadcycle@163.com
// -----------------------------------------------------------

using System;
using System.Collections.Generic;

using UnityEngine;
using UnityEngine.Pool;

namespace UIWidget
{
    /// <summary>
    /// 可复用的滚动视图控件(Cell尺寸一致, 使用同一个模板)。
    /// 使用须知:
    ///     需要运行时, 动态控制Cell的渲染更新, 需要设置 `SetCellGetScriptType`
    /// </summary>
    [DisallowMultipleComponent]
    public class FixedScrollRect : ScrollRectBase
    {
        #region 字段
        [SerializeField]
        private Vector2 m_CellSize = Vector2.zero;

        [SerializeField]
        private GameObject m_CellTemplate;

        private Type m_CellScriptType;
        private ObjectPool<RectTransform> m_CachedInstancePool;

        private readonly Dictionary<RectTransform, CellBase> m_CellScripts =
            new Dictionary<RectTransform, CellBase>();
        #endregion

        /// <summary>
        /// 设置Cell处理渲染更新的脚本。
        /// </summary>
        public void SetScriptType(Type scriptType)
        {
            if (scriptType == null)
            {
                throw new ArgumentNullException(nameof(scriptType));
            }

            if (!typeof(CellBase).IsAssignableFrom(scriptType))
            {
                throw new ArgumentNullException(nameof(scriptType));
            }

            m_CellScriptType = scriptType;
        }

        /// <summary>
        /// 获取Cell的Size。
        /// </summary>
        /// <param name="index">Cell的索引。</param>
        protected override Vector2 GetCellSize(int index)
        {
            return m_CellSize;
        }

        /// <summary>
        /// 将复用Cell实例分配给对应索引。 
        /// </summary>
        /// <param name="index">索引值。</param>
        /// <param name="cellInstance">复用Cell实例。</param>
        protected override void SetInstanceForIndex(int index, RectTransform cellInstance)
        {
            base.SetInstanceForIndex(index, cellInstance);

            if (m_CellScriptType == null)
            {
                return;
            }

            if (!m_CellScripts.TryGetValue(cellInstance, out CellBase cellScript))
            {
                if (!cellInstance.TryGetComponent(out cellScript))
                {
                    cellScript = (CellBase)cellInstance.gameObject.AddComponent(m_CellScriptType);
                }

                if (cellScript != null)
                {
                    m_CellScripts.Add(cellInstance, cellScript);
                }
            }

            m_ManagedCellDatas[index].CellScript = cellScript;
        }

        /// <summary>
        /// 初始化管理同一种实例的对象池。
        /// </summary>
        protected override void InitInstancePool()
        {
            if (m_CachedInstancePool != null)
            {
                return;
            }

#if UNITY_EDITOR
            m_CachedInstancePool = new ObjectPool<RectTransform>(OnPoolCreateInstance,
                actionOnRelease: OnPoolReleaseInstance,
                actionOnDestroy: OnPoolDestroyInstance,
                collectionCheck: k_EnableDebug,
                defaultCapacity: m_PoolCapacity);
#else
            m_CachedInstancePool = new ObjectPool<RectTransform>(OnPoolCreateInstance,
                actionOnRelease: OnPoolReleaseInstance,
                actionOnDestroy: OnPoolDestroyInstance,
                collectionCheck: false,
                defaultCapacity: m_PoolCapacity);
#endif
        }

        protected override void ClearInstancePool()
        {
            if (m_CachedInstancePool == null)
            {
                return;
            }

            m_CachedInstancePool.Clear();
            m_CachedInstancePool = null;
        }

        /// <summary>
        ///  对象池获取对象时, 需要创建新的对象时回调。
        /// </summary>
        protected override RectTransform OnPoolCreateInstance()
        {
            if (m_CellTemplate == null)
            {
                throw new NullReferenceException("Cell template is null. (未设置预制体模板)");
            }

            GameObject instance = Instantiate(m_CellTemplate, content.transform);
            RectTransform rectTransform = instance.GetComponent<RectTransform>();

            rectTransform.anchorMin = Vector2.up;
            rectTransform.anchorMax = Vector2.up;
            rectTransform.pivot = Vector2.zero;

            if (!instance.activeSelf)
            {
                instance.SetActive(true);
            }

            return rectTransform;
        }

        /// <summary>
        /// 如何获取Cell对象实例。
        /// </summary>
        /// <param name="index">索引。</param>
        protected override RectTransform GetCellInstance(int index)
        {
            RectTransform cellInstance = null;

            if (!GetCellInstanceCustom(index, ref cellInstance))
            {
                cellInstance = m_CachedInstancePool.Get();
            }

#if UNITY_EDITOR
            if (cellInstance != null && k_EnableDebug)
            {
                cellInstance.gameObject.name = $"[{index}]";
            }
#endif
            return cellInstance;
        }

        /// <summary>
        /// 回收Cell对象。
        /// </summary>
        /// <param name="instance">Cell对象。</param>
        protected override void RecycleCellInstance(RectTransform instance)
        {
            if (RecycleInstanceCustom(instance))
            {
                return;
            }

            m_CachedInstancePool.Release(instance);
        }
    }
}